• 2022-08-27
  • unique

Single Host Service

One Server all the services

single host service

update system and instal deps

apt -y update && apt -y upgrade && apt -y autoremove && apt -y autoclean
apt -y dist-upgrade
# install base deps
apt install vim apt-transport-https lsb-release ca-certificates wget zstd git 
# install pam deps
apt install libpam0g-dev gcc libc6-dev make scdoc

install knot

wget -O /etc/apt/trusted.gpg.d/knot-latest.gpg https://deb.knot-dns.cz/knot-latest/apt.gpg
sh -c 'echo "deb https://deb.knot-dns.cz/knot-latest/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/knot-latest.list'
apt -y update
apt -y install knot knot-dnsutils

mv /etc/knot/knot.conf{,.old}
cp conf/knot.conf /etc/knot/

setup zone in knot

# define the folliwing variables
# DOMAIN="example.com"
# IPV4="127.0.0.1"
# IPV6="::1"

knotc zone-begin ${DOMAIN}.

knotc zone-set -- @ 86400 SOA ${DOMAIN}. root.${DOMAIN}. 2021022500 14400 3600 1209600 3600
knotc zone-set -- @ 86400 NS ${DOMAIN}.

knotc zone-set -- @ 7200 A ${IPV4}
knotc zone-set -- * 7200 A ${IPV4}
knotc zone-set -- @ 7200 AAAA ${IPV6}
knotc zone-set -- * 7200 AAAA ${IPV6}

knotc zone-set -- @ 7200 MX 10 ${DOMAIN}.
knotc zone-set -- * 7200 MX 10 ${DOMAIN}.

knotc zone-set -- @ 7200 TXT "\"v=spf1 mx -all\""
knotc zone-set -- @ 7200 CAA 0 issue "\"letsencrypt.org\""
knotc zone-set -- @ 7200 CAA 0 issue "\"mailto:root@${DOMAIN}\""
knotc zone-set -- _dmarc 7200 TXT "\"v=DMARC1; p=reject; rua=mailto:root@${DOMAIN}; ruf=mailto:root@${DOMAIN};\""
knotc zone-set -- *._domainkey 7200 TXT "\"v=DKIM1; p=\""

knotc zone-set -- _autodiscover._tcp 7200 SRV 0 0 443 autodiscover

knotc zone-set -- _mta-sts 7200 TXT "\"v=STSv1; id=20210228002000Z\""
knotc zone-set -- _smtp._tls 7200 TXT "\"v=TLSRPTv1; rua=mailto:root@${DOMAIN}\""

knotc zone-commit --

install acme.sh

mkdir -p /opt/src
cd /opt/src
git clone https://github.com/acmesh-official/acme.sh.git
cd acme.sh/
./acme.sh --install --home /opt/cert --accountemail "root@${DOMAIN}"
source /opt/cert/acme.sh.env

export KNOT_SERVER="::1"
export KNOT_KEY="hmac-sha384:tsigkey1:example"
acme.sh --issue -d ${DOMAIN} -d *.${DOMAIN} --dns dns_knot

# later you can install the certificate with the follwing command
acme.sh --force --install-cert -d ${DOMAIN} --key-file /etc/maddy/certs/${DOMAIN}/privkey.pem --fullchain-file /etc/maddy/certs/${DOMAIN}/fullchain.pem

install maddy

# install recent golang version
cd /opt/src
wget https://golang.org/dl/go1.16.linux-amd64.tar.gz
tar xf go1.16.linux-amd64.tar.gz 
export GOROOT="$PWD/go"
export PATH="$PWD/go/bin:$PATH"

# install maddy

git clone https://github.com/foxcpp/maddy.git
cd maddy/
git checkout v0.4.3
./build.sh 
./build.sh install

configure maddy

# dns knot
# set variable
# DOMAIN="example.com"

knotc zone-begin ${DOMAIN}.
knotc zone-set -- default._domainkey 7200 TXT "\"`cat /var/lib/maddy/dkim_keys/*_default.dns`\""
knotc zone-commit --

maddy conf

## Maddy Mail Server - default configuration file (2020-10-11)
# Suitable for small-scale deployments. Uses its own format for local users DB,
# should be managed via maddyctl utility.
# ----------------------------------------------------------------------------
# Base variables

$(hostname) = example.com
$(primary_domain) = $(hostname)
$(local_domains) = $(primary_domain)

tls file /etc/maddy/certs/$(hostname)/fullchain.pem /etc/maddy/certs/$(hostname)/privkey.pem

# ----------------------------------------------------------------------------
auth.pam {
    debug no
    use_helper no
}


# imapsql module stores all indexes and metadata necessary for IMAP using a
# relational database. It is used by IMAP endpoint for mailbox access and
# also by SMTP & Submission endpoints for delivery of local messages.

storage.imapsql local_mailboxes {
    driver sqlite3
    dsn imapsql.db
}

# ----------------------------------------------------------------------------
# SMTP endpoints + message routing

hostname $(hostname)

msgpipeline local_routing {

    destination postmaster $(local_domains) {
        modify {
            replace_rcpt file /etc/maddy/aliases
            replace_rcpt regexp "(.+)[\.\_\+\-](.+)@(.+)" "$1@$3"
            replace_rcpt regexp "(.+)@(.+)\.$(primary_domain)" "$1@$(primary_domain)"
        }

        deliver_to &local_mailboxes
    }

    default_destination {
        reject 550 5.1.1 "User doesn't exist"
    }
}

smtp tcp://0.0.0.0:25 {
    limits {
        # Up to 20 msgs/sec across max. 10 SMTP connections.
        all rate 20 1s
        all concurrency 10
    }

    dmarc yes
    check {
        require_mx_record
        dkim
        spf
    }

    source $(local_domains) {
        reject 501 5.1.8 "Use Submission for outgoing SMTP"
    }
    default_source {
        destination postmaster $(local_domains) {
            deliver_to &local_routing
        }
        default_destination {
            reject 550 5.1.1 "User doesn't exist"
        }
    }
}

submission tls://0.0.0.0:465 tcp://0.0.0.0:587 {
    limits {
        # Up to 50 msgs/sec across any amount of SMTP connections.
        all rate 50 1s
    }

    auth pam

    source $(local_domains) {
        destination postmaster $(local_domains) {
            deliver_to &local_routing
        }
        default_destination {
            modify {
                dkim $(primary_domain) $(local_domains) default
            }
            deliver_to &remote_queue
        }
    }
    default_source {
        reject 501 5.1.8 "Non-local sender domain"
    }
}

target.remote outbound_delivery {
    limits {
        # Up to 20 msgs/sec across max. 10 SMTP connections
        # for each recipient domain.
        destination rate 20 1s
        destination concurrency 10
    }
    mx_auth {
        dane
        mtasts {
            cache fs
            fs_dir mtasts_cache/
        }
        local_policy {
            min_tls_level encrypted
            min_mx_level none
        }
    }
}

target.queue remote_queue {
    target &outbound_delivery

    autogenerated_msg_domain $(primary_domain)
    bounce {
        destination postmaster $(local_domains) {
            deliver_to &local_routing
        }
        default_destination {
            reject 550 5.0.0 "Refusing to send DSNs to non-local addresses"
        }
    }
}

# ----------------------------------------------------------------------------
# IMAP endpoints

imap tls://0.0.0.0:993 tcp://0.0.0.0:143 {
    auth pam
    storage &local_mailboxes
}

what mail adresses work with maddy

for the user with the username “test” sending and receiving on:

  • user@${DOMAIN}
  • test+asd@${DOMAIN}
  • test-asd@${DOMAIN}
  • test.asd@${DOMAIN}
  • test_asd@${DOMAIN} only receiving on:
  • test@asd.${DOMAIN}
  • test+asd@asd.${DOMAIN}
  • test-asd@asd.${DOMAIN}
  • test.asd@asd.${DOMAIN}
  • test_asd@asd.${DOMAIN}

create system mail addresses

# set variable
# DOMAIN="example.com"
# USERNAME="root"
./aliases.sh ${DOMAIN} ${USERNAME} > /etc/maddy/aliases

aliases.sh

DOMAIN=$1
USER=$2
cat <<_EOF_
info@${DOMAIN}: ${USER}@${DOMAIN}
support@${DOMAIN}: ${USER}@${DOMAIN}
abuse@${DOMAIN}: ${USER}@${DOMAIN}
noc@${DOMAIN}: ${USER}@${DOMAIN}
security@${DOMAIN}: ${USER}@${DOMAIN}
postmaster@${DOMAIN}: ${USER}@${DOMAIN}
hostmaster@${DOMAIN}: ${USER}@${DOMAIN}
webmaster@${DOMAIN}: ${USER}@${DOMAIN}
admin@${DOMAIN}: ${USER}@${DOMAIN}
${DOMAIN}@${DOMAIN}: ${USER}@${DOMAIN}
_EOF_

install and configure nginx

# set variable
# DOMAIN="example.com"
rm -rf /etc/nginx/*
./nginx.conf.sh ${DOMAIN} > /etc/nginx/nginx.conf

nginx.conf.sh

DOMAIN=$1
cat <<_EOF_
user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
        worker_connections 768;
        multi_accept on;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server_tokens off;

    # server_names_hash_bucket_size 64;
    # server_name_in_redirect off;
    types {
        text/html                             html htm shtml;
        text/css                              css;
        text/xml                              xml;
        image/gif                             gif;
        image/jpeg                            jpeg jpg;
        application/javascript                js;
        application/atom+xml                  atom;
        application/rss+xml                   rss;

        text/mathml                           mml;
        text/plain                            txt;
        text/vnd.sun.j2me.app-descriptor      jad;
        text/vnd.wap.wml                      wml;
        text/x-component                      htc;

        image/png                             png;
        image/tiff                            tif tiff;
        image/vnd.wap.wbmp                    wbmp;
        image/x-icon                          ico;
        image/x-jng                           jng;
        image/x-ms-bmp                        bmp;
        image/svg+xml                         svg svgz;
        image/webp                            webp;

        application/font-woff                 woff;
        application/java-archive              jar war ear;
        application/json                      json;
        application/mac-binhex40              hqx;
        application/msword                    doc;
        application/pdf                       pdf;
        application/postscript                ps eps ai;
        application/rtf                       rtf;
        application/vnd.apple.mpegurl         m3u8;
        application/vnd.ms-excel              xls;
        application/vnd.ms-fontobject         eot;
        application/vnd.ms-powerpoint         ppt;
        application/vnd.wap.wmlc              wmlc;
        application/vnd.google-earth.kml+xml  kml;
        application/vnd.google-earth.kmz      kmz;
        application/x-7z-compressed           7z;
        application/x-cocoa                   cco;
        application/x-java-archive-diff       jardiff;
        application/x-java-jnlp-file          jnlp;
        application/x-makeself                run;
        application/x-perl                    pl pm;
        application/x-pilot                   prc pdb;
        application/x-rar-compressed          rar;
        application/x-redhat-package-manager  rpm;
        application/x-sea                     sea;
        application/x-shockwave-flash         swf;
        application/x-stuffit                 sit;
        application/x-tcl                     tcl tk;
        application/x-x509-ca-cert            der pem crt;
        application/x-xpinstall               xpi;
        application/xhtml+xml                 xhtml;
        application/xspf+xml                  xspf;
        application/zip                       zip;

        application/octet-stream              bin exe dll;
        application/octet-stream              deb;
        application/octet-stream              dmg;
        application/octet-stream              iso img;
        application/octet-stream              msi msp msm;

        application/vnd.openxmlformats-officedocument.wordprocessingml.document    docx;
        application/vnd.openxmlformats-officedocument.spreadsheetml.sheet          xlsx;
        application/vnd.openxmlformats-officedocument.presentationml.presentation  pptx;

        audio/midi                            mid midi kar;
        audio/mpeg                            mp3;
        audio/ogg                             ogg;
        audio/x-m4a                           m4a;
        audio/x-realaudio                     ra;

        video/3gpp                            3gpp 3gp;
        video/mp2t                            ts;
        video/mp4                             mp4;
        video/mpeg                            mpeg mpg;
        video/quicktime                       mov;
        video/webm                            webm;
        video/x-flv                           flv;
        video/x-m4v                           m4v;
        video/x-mng                           mng;
        video/x-ms-asf                        asx asf;
        video/x-ms-wmv                        wmv;
        video/x-msvideo                       avi;
    }

    default_type application/octet-stream;

    ssl_protocols TLSv1.2;
    ssl_prefer_server_ciphers on;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    gzip on;

    server {
        listen 80 default_server;
        listen [::]:80 default_server;
	listen 443 default_server ssl http2;
	listen [::]:443 default_server ssl http2;

	ssl_certificate /opt/cert/${DOMAIN}/fullchain.cer;
	ssl_certificate_key /opt/cert/${DOMAIN}/${DOMAIN}.key;

        root /var/www/html;

        index index.html index.htm;
        server_name ${DOMAIN};

        set \$redirect false;
        # enable this to only allow main domain
        #if ( \$host != \$server_name) {
        #  set \$redirect true;
        #}
        if ( \$scheme = http ) {
          set \$redirect true;
        }
        if ( \$request_uri ~* '/.well-known/acme-challenge/' ) {
          set \$redirect false;
        }
        if ( \$redirect = true) {
          return 302 https://\$server_name\$request_uri;
        }

        location / {
            try_files \$uri \$uri/ =404;
        }
        location ~ ^/~(.+?)(/.*)?$ {
            alias /home/\$1/www\$2;
            #autoindex on;
        }
        location ~ /\\.(?!well-known).* {
            deny all;
            access_log off;
            log_not_found off;
        }
        location = /.well-known/mta-sts.txt {
            return 200 "version: STSv1\nmode: enforce\nmax_age: 10368000\nmx: ${DOMAIN}\n";
        }
	location /autodiscover/autodiscover.xml {
	    alias /var/www/html/autodiscover.xml;
        }
	location /.well-known/autoconfig/mail/config-v1.1.xml {
            alias /var/www/html/config-v1.1.xml;
        }
        location /mail/config-v1.1.xml {
            alias /var/www/html/config-v1.1.xml;
        }
    } 
}
_EOF_

configure sshd

# uncoment the default sftp Subsystem
# add Deny and Chroot options
cat <<'_EOF_' >> /etc/ssh/sshd_config

#Subsystem      sftp    /usr/lib/openssh/sftp-server

Subsystem       sftp    internal-sftp

Port 2222

Match Group sftponly LocalPort 22
    DenyGroups sftponly

Match Group sftponly
    ChrootDirectory %h
    AllowTCPForwarding no
    X11Forwarding no
    ForceCommand internal-sftp
    PasswordAuthentication no
_EOF_


useradd -G sftponly -s /sbin/nologin -m -k ./user-skel/ ${USERNAME}
chown root: /home/${USERNAME}

autodiscover

# set variable
# DOMAIN="example.com"

./autodiscover.xml.sh ${DOMAIN} > /var/www/html/autodiscover.xml
./config-v1.1.xml.sh ${DOMAIN} > /var/www/html/config-v1.1.xml

autodiscover.xml.sh

DOMAIN=$1
cat <<_EOF_
<?xml version="1.0" encoding="UTF-8"?>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
    <Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
        <Account>
            <AccountType>email</AccountType>
            <Action>settings</Action>
            <Protocol>
                <Type>IMAP</Type>
                <Server>${DOMAIN}</Server>
                <Port>993</Port>
                <DomainRequired>on</DomainRequired>
                <SPA>off</SPA>
                <SSL>on</SSL>
                <AuthRequired>on</AuthRequired>
            </Protocol>
            <Protocol>
                <Type>SMTP</Type>
                <Server>${DOMAIN}</Server>
                <Port>465</Port>
                <DomainRequired>on</DomainRequired>
                <SPA>off</SPA>
                <SSL>on</SSL>
                <AuthRequired>on</AuthRequired>
                <UsePOPAuth>off</UsePOPAuth>
                <SMTPLast>off</SMTPLast>
            </Protocol>
        </Account>
    </Response>
</Autodiscover>
_EOF_

config-v1.1.xml.sh

DOMAIN=$1
cat <<_EOF_
<?xml version="1.0"?>
<clientConfig version="1.1">
  <emailProvider id="${DOMAIN}">
    <domain>${DOMAIN}</domain>
    <displayName>${DOMAIN} Mail</displayName>
    <displayShortName>${DOMAIN}</displayShortName>
    <incomingServer type="imap">
      <hostname>${DOMAIN}</hostname>
      <port>993</port>
      <socketType>SSL</socketType>
      <authentication>password-cleartext</authentication>
      <username>%EMAILADDRESS%</username>
    </incomingServer>
    <incomingServer type="imap">
      <hostname>${DOMAIN}</hostname>
      <port>143</port>
      <socketType>STARTTLS</socketType>
      <authentication>password-cleartext</authentication>
      <username>%EMAILADDRESS%</username>
    </incomingServer>
    <outgoingServer type="smtp">
      <hostname>${DOMAIN}</hostname>
      <port>465</port>
      <socketType>SSL</socketType>
      <authentication>password-cleartext</authentication>
      <username>%EMAILADDRESS%</username>
    </outgoingServer>
    <outgoingServer type="smtp">
      <hostname>${DOMAIN}</hostname>
      <port>587</port>
      <socketType>STARTTLS</socketType>
      <authentication>password-cleartext</authentication>
      <username>%EMAILADDRESS%</username>
    </outgoingServer>
    <documentation url="https://${DOMAIN}">
      <descr lang="de">Webseite von ${DOMAIN}</descr>
      <descr lang="en">Homepage of ${DOMAIN}</descr>
    </documentation>
  </emailProvider>
</clientConfig>
_EOF_

homepage

# set variable
# DOMAIN="example.com"

./index.htm.sh ${DOMAIN} > /var/www/html/index.html

ToDo

needed:

other: